package com.wzs.rpc.protocol;

import com.wzs.rpc.constant.RpcConstant;
import com.wzs.rpc.model.RpcRequest;
import com.wzs.rpc.model.RpcResponse;
import com.wzs.rpc.serializer.Serializer;
import com.wzs.rpc.serializer.SerializerFactory;
import io.vertx.core.buffer.Buffer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@Slf4j
public class ProtocolMessageDecoder {
    public static ProtocolMessage<?> decode(Buffer buffer) throws IOException {
        byte magic = buffer.getByte(0);
        if (magic!=ProtocolConstant.PROTOCOL_MAGIC) {
            log.error("消息 magic({}) 非法", magic);
            throw new RuntimeException("消息 magic 非法");
        }
        ProtocolMessage.Header header = ProtocolMessage.Header.builder()
                .magic(magic)
                .version(buffer.getByte(1))
                .serializer(buffer.getByte(2))
                .type(buffer.getByte(3))
                .status(buffer.getByte(4))
                .requestId(buffer.getLong(5))
                .bodyLength(buffer.getInt(13))
                .build();
        byte[] bytes = buffer.getBytes(17, 17 + header.getBodyLength());

        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByValue(header.getSerializer());
        if (serializerEnum==null) {
            log.error("序列化器不存在");
            throw new RuntimeException("序列化器不存在");
        }
        Serializer serializer = SerializerFactory.getInstance(serializerEnum.getName());

        ProtocolMessageTypeEnum typeEnum = ProtocolMessageTypeEnum.getEnumByValue(header.getType());
        if (typeEnum==null) {
            log.error("序列化消息的类型不存在");
            throw new RuntimeException("序列化消息的类型不存在");
        }
        switch (typeEnum) {
            case REQUEST:
                RpcRequest rpcRequest = serializer.deserialize(bytes, RpcRequest.class);
                return new ProtocolMessage<>(header, rpcRequest);
            case RESPONSE:
                RpcResponse rpcResponse = serializer.deserialize(bytes, RpcResponse.class);
                return new ProtocolMessage<>(header, rpcResponse);
            case HEART_BEAT:
            case OTHERS:
            default:
                log.error("暂不支持该消息消息类型：" + typeEnum.name());
                throw new RuntimeException("暂不支持该消息消息类型：" + typeEnum.name());
        }
    }
}
